
#include <ddk.h>

#include "CUffsFile.h"
#define IncrementDllLockCount() do {} while(0)
#define DecrementDllLockCount() do {} while(0)

#include "_CUffsFile.cpp"

#include "uffserrors.h"


CUffsFile::CUffsFile()
{
    m_bInited = FALSE;
}

ECode CUffsFile::Initialize(uffs_Object *objHandle)
{
    int size = sizeof(uffs_Object);
    memset(&m_objHandle, 0, size);
    memcpy(&m_objHandle, objHandle, size);
    m_bInited = TRUE;

    return NOERROR;
}

CUffsFile::~CUffsFile()
{
    if (m_bInited) {
        uffs_CloseObject(&m_objHandle);
    }
}

ECode CUffsFile::GetObjectInfo(int type, Int32 *pData)
{
    URET ret;
    uffs_ObjectInfo info;

    if (!pData) {
        return E_INVALID_ARGUMENT;
    }

    memset(&info, 0, sizeof(uffs_ObjectInfo));

    ret = uffs_GetObjectInfo(&m_objHandle, &info);
    if (ret != U_SUCC) {
        *pData = NULL;
        return -1;
    }

    switch(type) {
        case ACC_TIME:
            *pData = info.info.access;
            break;
        case MOD_TIME:
            *pData = info.info.lastModify;
            break;
        case CRE_TIME:
            *pData = info.info.createTime;
            break;
        case ACC_MODE:
        case SHA_MODE:
            *pData = info.info.attr;
            break;
        default:
            return E_INVALID_ARGUMENT;
    }

    return NOERROR;
}

ECode CUffsFile::Read(
    /* [in] */ Int32 offset,
    /* [in] */ Int32 toRead,
    /* [out] */ MemoryBuf * pBuf)
{
    URET ret;

    if (NULL == pBuf || offset < 0 || toRead < 0
        || toRead > pBuf->GetCapacity()) {
        return E_INVALID_ARGUMENT;
    }

    if (toRead == 0) {
        return NOERROR;
    }

	ret = uffs_ReadObject(&m_objHandle, pBuf->GetPayload(), offset, toRead);

	pBuf->SetUsed(ret);

    if (ret == 0) {
        return E_INVALID_ARGUMENT;
    }

	return NOERROR;
}

ECode CUffsFile::Write(
    /* [in] */ Int32 offset,
    /* [in] */ const MemoryBuf & ezbBuf,
    /* [out] */ Int32 * pWrite)
{
    URET ret;

    if (ezbBuf.IsNullOrEmpty() || NULL == pWrite || offset < 0) {
        return E_INVALID_ARGUMENT;
    }

    ret = uffs_WriteObject(&m_objHandle, ezbBuf.GetPayload(), offset, ezbBuf.GetUsed());
    *pWrite = ret;
    if (ret != ezbBuf.GetUsed()) {
        if (m_objHandle.err == UESHARE) {
            return E_FS_FILE_BUSY;
        } else if (m_objHandle.err == UEACCESS) {
            return E_FS_NO_PERMISSION;
        } else if (m_objHandle.err == UENOSPACE) {
            return E_FS_NO_SPACE;
        } else {
            return E_UFFS_WRITE;
        }
    }

    m_objHandle.oflag |= UO_WRONLY;

	return NOERROR;
}

ECode CUffsFile::GetSize(
    /* [out] */ Int32  * pSize)
{
    uffs_ObjectInfo info;

    if (pSize == NULL) {
        return E_INVALID_ARGUMENT;
    }

    URET ret = uffs_GetObjectInfo(&m_objHandle, &info);

    if (ret == U_FAIL) {
        return E_UFFS_UNKOWN;
    }

    *pSize = info.len;

    return NOERROR;
}

ECode CUffsFile::SetSize(
    /* [in] */ Int32  size)
{
    URET ret = uffs_SetObjectSize(&m_objHandle, size);
    if (ret != U_SUCC) {
        if (m_objHandle.err == UESHARE) {
            return E_FS_FILE_BUSY;
        } else if (m_objHandle.err == UEACCESS) {
            return E_FS_NO_PERMISSION;
        } else if (m_objHandle.err == UENOSPACE) {
            return E_FS_NO_SPACE;
        } else {
            return E_UFFS_WRITE;
        }
    }

    m_objHandle.oflag |= UO_WRONLY;

    return NOERROR;
}

ECode CUffsFile::GetOptimalBlockSize(
    /* [out] */ Int32  * pSize)
{
    if (NULL == pSize) {
        return E_INVALID_ARGUMENT;
    }

    *pSize = m_objHandle.dev->attr.block_data_size;
    return NOERROR;
}

ECode CUffsFile::Sync()
{
    if (uffs_SyncObject(&m_objHandle) == U_SUCC) {
        m_objHandle.oflag &= (~UO_WRONLY);
        return NOERROR;
    }

    return E_UFFS_SYNC;
}

ECode CUffsFile::GetType(
    /* [out] */ FileType * pType)
{
    if (pType == NULL) {
        return E_INVALID_ARGUMENT;
    }

    *pType = FileType_RegularFile;

    return NOERROR;
}

ECode CUffsFile::GetAccessTime(
    /* [out] */ Int32 * pTime)
{
    if (pTime == NULL) {
        return E_INVALID_ARGUMENT;
    }


    return GetObjectInfo(ACC_TIME, pTime);
}

ECode CUffsFile::SetAccessTime(
    /* [in] */ Int32 time)
{
    if (time < SECONDSTO1980_UFFS) {
        return E_INVALID_ARGUMENT;
    }

    if (U_SUCC != uffs_SetObjectInfo(&m_objHandle, time, ACC_TIME)) {
        if (m_objHandle.err == UEACCESS) {
            return E_FS_NO_PERMISSION;
        } else if (m_objHandle.err == UESHARE) {
            return E_FS_FILE_BUSY;
        } else {
            return E_UFFS_UNKOWN;
        }
    }

    return NOERROR;
}

ECode CUffsFile::GetModificationTime(
    /* [out] */ Int32 * pTime)
{
    if (pTime == NULL) {
        return E_INVALID_ARGUMENT;
    }

    return GetObjectInfo(MOD_TIME, pTime);
}

ECode CUffsFile::SetModificationTime(
        /* [in] */ Int32 time)
{
    if (time < SECONDSTO1980_UFFS) {
        return E_INVALID_ARGUMENT;
    }

    if (U_SUCC != uffs_SetObjectInfo(&m_objHandle, time, MOD_TIME)) {
        if (m_objHandle.err == UEACCESS) {
            return E_FS_NO_PERMISSION;
        } else if (m_objHandle.err == UESHARE) {
            return E_FS_FILE_BUSY;
        } else {
            return E_UFFS_UNKOWN;
        }
    }

    return NOERROR;
}

ECode CUffsFile::GetCreateTime(
    /* [out] */ Int32 * pTime)
{
    if (pTime == NULL) {
        return E_INVALID_ARGUMENT;
    }

    return GetObjectInfo(CRE_TIME, pTime);
}

ECode CUffsFile::CheckAccessMode(
    /* [in] */ FileAccessMode mode)
{
    Int32 attr;
    ECode ec;

    if (mode != FileAccessMode_Read
        && mode != FileAccessMode_ReadWrite
        && mode != FileAccessMode_Write)
    {
        return E_INVALID_ARGUMENT;
    }

    if (m_objHandle.serial == ROOT_DIR_ID) {
        return NOERROR;
    }

    ec = GetObjectInfo(ACC_MODE, &attr);
    if (ec != NOERROR) {
        kprintf("GetObjectInfo FAILED\n");
        return ec;
    }

    if (mode == FileAccessMode_Read && (attr & UA_RDONLY)) {
        return NOERROR;
    }
    else
    if (attr & UA_RDWR) {
        return NOERROR;
    }

    return E_FS_NO_PERMISSION;
}

ECode CUffsFile::GetAccessMode(
    /* [out] */ FileAccessMode * pMode)
{
    Int32 attr;
    ECode ec;

    if (pMode == NULL) {
        return E_INVALID_ARGUMENT;
    }

    ec = GetObjectInfo(ACC_MODE, &attr);
    if (ec != NOERROR) {
        return ec;
    }

    if (attr & UA_RDONLY) {
        *pMode =  FileAccessMode_Read;
    }
    else
    if (attr & UA_RDWR) {
        *pMode = FileAccessMode_ReadWrite;
    }
    else {
        assert(0);
    }

    return NOERROR;
}

ECode CUffsFile::SetAccessMode(
    /* [in] */ FileAccessMode mode)
{
    UInt32 attr = 0;

    if (mode != FileAccessMode_ReadWrite
        && mode != FileAccessMode_Read
        && mode != FileAccessMode_Write)
    {
        return E_INVALID_ARGUMENT;
    }

    switch(mode) {
        case FileAccessMode_ReadWrite:
        case FileAccessMode_Write:
            attr |= UA_RDWR;
            break;
        case FileAccessMode_Read:
            attr |= UA_RDONLY;
            break;
    }

    if (U_SUCC != uffs_SetObjectInfo(&m_objHandle, attr, ACC_MODE)) {
        if (m_objHandle.err == UEACCESS) {
            return E_FS_NO_PERMISSION;
        } else if (m_objHandle.err == UESHARE) {
            return E_FS_FILE_BUSY;
        } else {
            return E_UFFS_UNKOWN;
        }
    }

    return NOERROR;
}

ECode CUffsFile::GetShareMode(
    /* [out] */ FileShareMode *pMode)
{
    Int32 attr;
    ECode ec;

    if (pMode == NULL) {
        return E_INVALID_ARGUMENT;
    }

    ec = GetObjectInfo(SHA_MODE, &attr);
    if (ec != NOERROR) {
        return ec;
    }

    if (attr & US_WRITE) {
        *pMode = FileShareMode_Write;
    }
    else
    if (attr & US_READ) {
        *pMode = FileShareMode_Read;
    }
    else
    if (attr & US_DENY) {
        *pMode = FileShareMode_Deny;
    }
    else {
        assert(0);
    }

    return NOERROR;
}

ECode CUffsFile::SetShareMode(
    /* [in] */ FileShareMode mode)
{
    UInt32 attr = 0;

    if (mode != FileShareMode_Write
        && mode != FileShareMode_Read
        && mode != FileShareMode_Deny)
    {
        return E_INVALID_ARGUMENT;
    }

    switch(mode) {
        case FileShareMode_Write:
            attr |= US_WRITE;
			break;
        case FileShareMode_Deny:
            attr |= US_DENY;
            break;
        case FileShareMode_Read:
            attr |= US_READ;
            break;
    }

    if (U_SUCC != uffs_SetObjectInfo(&m_objHandle, attr, SHA_MODE)) {
        if (m_objHandle.err == UEACCESS) {
            return E_FS_NO_PERMISSION;
        } else if (m_objHandle.err == UESHARE) {
            return E_FS_FILE_BUSY;
        } else {
            return E_UFFS_UNKOWN;
        }
    }

    return NOERROR;
}

ECode CUffsFile::AddFileMonitor(
    /* [out] */ IEvent **ppEvent)
{
    if (NULL == ppEvent) {
        return E_INVALID_ARGUMENT;
    }

    int pEvent = 0;
    URET ret = uffs_AddMonitor(m_objHandle.dev, m_objHandle.node, &pEvent);
    if (ret != U_SUCC) {
        return E_UFFS_MONITOR;
    }

    *ppEvent = (IEvent*)pEvent;
    return NOERROR;
}

ECode CUffsFile::RemoveFileMonitor(
    /* [in] */ IEvent *pEvent)
{
    int event = (int)pEvent;

    if (event == 0) {
        return E_INVALID_ARGUMENT;
    }

    URET ret = uffs_RemoveMonitor(m_objHandle.dev, m_objHandle.node, event);
    if (ret != U_SUCC) {
        return E_UFFS_MONITOR;
    }

    return NOERROR;
}

